import { reaction, makeAutoObservable } from 'mobx';
import { v4 as uuidv4 } from 'uuid';
import Command from './Command';

// test模型，生成test项
export default class TestCase {
    id = null;

    name = null;

    commands = [];
    nameDialogShown = false;

    modified = false;

    selectedCommand = null;

    scrollY = null;

    constructor(id = uuidv4(), name = 'Untitled Test') {
        this.id = id;
        this.name = name;
        this.changeDisposer = reaction(
            () =>
                this.commands.map(({ command, target, targets, value }) => ({
                    command,
                    target,
                    targets,
                    value,
                })),
            () => {
                this.modified = true;
            },
        );
        this.export = this.export.bind(this);
        this.dispose = this.dispose.bind(this);

        makeAutoObservable(this, {}, { autoBind: true });
    }

    updateWindowHandleNames(oldValue, newValue) {
        const commands = this.commands;
        commands.forEach(function (kommand) {
            kommand.target = kommand.target.split(`\${${oldValue}}`).join(`\${${newValue}}`);
            kommand.value = kommand.value.split(`\${${oldValue}}`).join(`\${${newValue}}`);
        });
        this.commands = commands;
    }

    setName(name) {
        this.name = name;
        this.modified = true;
    }

    createCommand(index, c, t, v, comment) {
        if (index !== undefined && index.constructor.name !== 'Number') {
            throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
        } else {
            const command = new Command(undefined, c, t, v);
            command.addListener('window-handle-name-changed', this.updateWindowHandleNames);
            if (comment) command.setComment(comment);
            index !== undefined ? this.commands.splice(index, 0, command) : this.commands.push(command);
            return command;
        }
    }

    addCommand(command) {
        if (!command || !(command instanceof Command)) {
            throw new Error(`Expected to receive Command instead received ${command ? command.constructor.name : command}`);
        } else {
            command.addListener('window-handle-name-changed', this.updateWindowHandleNames);
            this.commands.push(command);
        }
    }

    insertCommandAt(command, index) {
        if (!command || !(command instanceof Command)) {
            throw new Error(`Expected to receive Command instead received ${command ? command.constructor.name : command}`);
        } else if (index === undefined || index.constructor.name !== 'Number') {
            throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
        } else {
            this.commands.splice(index, 0, command);
        }
    }

    swapCommands(from, to) {
        const command = this.commands.splice(from, 1)[0];
        this.insertCommandAt(command, to);
    }

    removeCommand(command) {
        command.removeListener('window-handle-name-changed', this.updateWindowHandleNames);
        this.commands.remove(command);
    }

    clearAllCommands() {
        this.commands.clear();
    }

    export() {
        return {
            id: this.id,
            name: this.name,
            commands: this.commands.map((c) => c.export()),
        };
    }

    dispose() {
        this.changeDisposer();
    }

    static fromJS = function (jsRep) {
        const test = new TestCase(jsRep.id);
        test.setName(jsRep.name);
        test.commands.replace(jsRep.commands.map(Command.fromJS));

        return test;
    };
}
